<?php
/**
 * @link https://ym2.cleverstone.top
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace extend\weixin;

use common\helper\App;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Response;
use yii\base\BaseObject;
use yii\helpers\ArrayHelper;
use yii\helpers\Json;

/**
 * 微信小程序-客户端
 * @auther clevstn
 * @since 2.0
 * @datetime 2023.11.22 13:07
 */
class WxMini extends BaseObject
{
    /**
     * @var array The api response result.
     */
    public $result;
    /**
     * @var null|string The api response error.
     */
    public $error;
    /**
     * @var false[] the default options with The request method.
     */
    public $defaultRequestOptions = [
        'verify' => false, //If verify ssl certificate.
    ];
    /**
     * @var array The defaults configuration whose pased in `GuzzleHttp\Client`.
     */
    protected static $defaults = [
        'base_uri' => 'https://api.weixin.qq.com/',
        'headers' => [
            'Accept' => 'application/json, text/plain, application/x-gzip, application/pdf, image/png, image/*;q=0.5',
            //'Content-Type' => 'application/json; charset=utf-8',
        ],
    ];
    /**
     * @var BaseMiniRequest the WeChat service instance.
     */
    private $_request;

    /**
     * @return bool Whether the interface responded incorrectly.
     */
    public function hasError()
    {
        return !empty($this->error);
    }

    /**
     * Set request
     * @param BaseMiniRequest $request
     * @return $this
     */
    public function setRequest(BaseMiniRequest $request)
    {
        $this->_request = $request;
        return $this;
    }

    /**
     * @param array $config Request options
     * @param string $businessType 业务类型
     * @param int $businessID 业务ID
     * @return mixed
     */
    public function execute($businessType, $businessID, array $config = [])
    {
        $methodAsync = $this->_request->getMethodAsync();
        $requestOptions = $this->_request->getRequestOptions();
        $client = new Client(
            array_replace_recursive(static::$defaults, $config)
        );
        $promise = $client->{$methodAsync}(
            $this->_request->getChain(),
            ArrayHelper::merge(
                $this->defaultRequestOptions,
                $requestOptions
            )
        )->then(function($response) {
            /** @var Response  $response */
            $fn = $this->_request->responseCallback($response, $this);
            if (is_callable($fn)) {
                // Format response to set $this result or error
                return $fn();
            } else {
                $this->result = Json::decode($response->getBody());
                return true;
            }
        })->otherwise(function ($e) {
            if ($e instanceof RequestException && $e->hasResponse()) {
                $body = Json::decode($e->getResponse()->getBody());
                $this->error = $body['message'];
            } else {
                $this->error = $e->getMessage();
            }
            return false;
        });
        $state = $promise->wait();
        ($this->_request->isLogged || $this->hasError()) && $this->log($requestOptions, $businessType, $businessID);

        return $state;
    }

    /**
     * @param array $requestOptions The request options
     * @param string $businessType 业务类型
     * @param int $businessID 业务ID
     * @return void
     */
    protected function log(array $requestOptions, $businessType, $businessID)
    {
        $serviceName = '【微信小程序】' . $this->_request->getServiceName();
        if ($this->hasError()) {
            App::logError($serviceName, [
                'Request' => $requestOptions,
                'Response' => $this->error,
            ], $businessType, $businessID);
        } else {
            App::logInfo($serviceName, [
                'Request' => $requestOptions,
                'Response' => $this->result,
            ], $businessType, $businessID);
        }
    }
}